package com.permission.service.impl;

import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Preconditions;
import com.permission.common.RequestHolder;
import com.permission.dao.SysDeptMapper;
import com.permission.dao.SysUserMapper;
import com.permission.entity.SysDept;
import com.permission.exception.ParamException;
import com.permission.param.DeptParam;
import com.permission.service.SysDeptService;
import com.permission.service.SysLogService;
import com.permission.util.BeanValidator;
import com.permission.util.IpUtil;
import com.permission.util.LevelUtil;

@Service("sysDeptService")
public class SysDeptServiceImpl implements SysDeptService {
	
	@Autowired
	private SysDeptMapper sysDeptMapper;
	
	@Autowired
    private SysUserMapper sysUserMapper;
	
	@Autowired
    private SysLogService sysLogService;
	
	/**
	 * 增加部门
	 */
	public void save(DeptParam dep) {
		BeanValidator.check(dep);		//验证参数
		if(checkExist(dep.getParentId(),dep.getName(),dep.getId())){
			throw new ParamException("同一层级下存在相同名称的部门");
		}
		
		//设置参数
		SysDept dept = SysDept.builder().name(dep.getName()).parentId(dep.getParentId())
				.seq(dep.getSeq()).remark(dep.getRemark()).build();
		
		//这个时候写一个工具类levelUtil，用于生成level
		//得到上一个部门的层级，再传入当前的id，再通过calculateLevel生成部门层级字符串
		dept.setLevel(LevelUtil.calculateLevel(getLevel(dep.getParentId()),dep.getParentId()));
		dept.setOperator(RequestHolder.getCurrentUser().getUsername());
        dept.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
        dept.setOperateTime(new Date());
		
		//执行添加
		sysDeptMapper.insertSelective(dept);
		
		//记录操作
		sysLogService.saveDeptLog(null, dept);
	}
	
	/**
	 * 检查部门是否存在
	 */
	private boolean checkExist(Integer parentId,String depName,Integer depId){
		return sysDeptMapper.countByNameAndParentId(parentId, depName, depId) > 0;
	}
	
	/**
	 * 根据部门ID获取部门level
	 * @param depId
	 * @return
	 */
	private String getLevel(Integer depId){
		SysDept dept = sysDeptMapper.selectByPrimaryKey(depId);
		if(dept == null){
			return null;
		}
		return dept.getLevel();
	}

	/**
	 * 更新部门
	 */
	public void update(DeptParam dep) {
		//参数校验
        BeanValidator.check(dep);		
        //根据ID取出要更新的部门
        SysDept before = sysDeptMapper.selectByPrimaryKey(dep.getId());
        //判断部门是否为空
        Preconditions.checkNotNull(before, "待更新的部门不存在");
        //判断是否有同名的部门
        if(checkExist(dep.getParentId(), dep.getName(), dep.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门");
        }

        //设置参数
        SysDept after = SysDept.builder().id(dep.getId()).name(dep.getName()).parentId(dep.getParentId())
                .seq(dep.getSeq()).remark(dep.getRemark()).build();
        after.setLevel(LevelUtil.calculateLevel(getLevel(dep.getParentId()), dep.getParentId()));                
        after.setOperator(RequestHolder.getCurrentUser().getUsername());
        after.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
        after.setOperateTime(new Date());
        
        updateWithChild(before, after);       
        sysLogService.saveDeptLog(before, after);
	}
	
	/**
     * 更新当前部门的同时更新子部门
     * @Transactionalj  该方法被事务管理，要么都成功，要么都失败
     * @param before    更新之前的部门
     * @param after     更新参数之后的部门
     */
    @Transactional
    private void updateWithChild(SysDept before, SysDept after) {
        String newLevelPrefix = after.getLevel();	//更新后部门的level前缀
        String oldLevelPrefix = before.getLevel();	//更新前部门的level前缀

        //如果after的level和before里面的level不一致的话(说明有更换父部门)，才会做子部门的更新
        if (!after.getLevel().equals(before.getLevel())) {
        	/*
        	 *获取该部门的所有子部门，这里level就可以派上用场了
        	 *例如：自己的id为1，上级id为0，那么自己的level为0.5，子部门的level为0.1.5 
        	 */
            List<SysDept> deptList = sysDeptMapper.getChildDeptListByLevel(oldLevelPrefix+"."+before.getId()+"%");
            if (CollectionUtils.isNotEmpty(deptList)) {
                //遍历子部门修改level
                for (SysDept dep : deptList) {
                    String level = dep.getLevel();
                    //如果是以oldLevelPrefix(更新前的level)为前缀的话，就进行更新
                    if (level.indexOf(oldLevelPrefix) == 0) {
                        //新的level= 新level的前缀+（去掉旧level前缀的level）
                        level = newLevelPrefix + level.substring(oldLevelPrefix.length());
                        dep.setLevel(level);
                    }
                }
                //执行批量更新
                sysDeptMapper.batchUpdateLevel(deptList);
            }
        }
        //最后更新该部门信息
        sysDeptMapper.updateByPrimaryKey(after);
    }

	
    /**
     * 删除部门
     */
    public void delete(Integer depId) {
    	SysDept dept = sysDeptMapper.selectByPrimaryKey(depId);
    	Preconditions.checkNotNull(dept, "待删除的部门不存在，无法删除");
        if (sysDeptMapper.countByParentId(dept.getId()) > 0) {
            throw new ParamException("当前部门下面有子部门，无法删除");
        }
        if(sysUserMapper.countByDeptId(dept.getId()) > 0) {
            throw new ParamException("当前部门下面有用户，无法删除");
        }
        sysDeptMapper.deleteByPrimaryKey(depId);
	}
}
